Modern computing systems manage access to shared resources (e.g., memory, disk storage, file systems, files, logical units of storage, etc.) on behalf of users and various internal and external functions. Some of these computing systems are able to recover from system failures such as power interruptions. However, not all resources are easily shared and doing so may complicate recovery after a system failure. For instance, if multiple processes attempt to modify a file simultaneously, it may be unclear how to restore that file if the system suffers a power interruption or hardware failure while that file (or other resource) is being modified. Such concurrency and resiliency problems can be addressed by allowing the computing system to execute only one process at any given time and tracking all attempted changes to the file. However, doing so would result in underutilizing the processing capacity of the system, causing poor system performance.
Conventional solutions to this problem allow the computing system to execute multiple independent processes (“threads”) while preventing more than one process from modifying any one resource at any given time by using resource locks. In response to a resource access request made by a first thread, the system can “lock” a resource such that only that thread can modify or otherwise access the resource at any given time. Other threads which do not require access to that locked resource can proceed uninterrupted. Such systems may periodically save backup data in nonvolatile memory (e.g., periodically “autosaving” a file being edited) to allow the system to recover certain data after a system failure.